//-----------------------------------------------
//	module name: arbMsg
//	author: Anping HE (heap@lzu.edu.cn)
//  modifier: Fu Tong , Baoxia Wan , Mingshu Chen ,Kang Li Zhao
//	version: 4st version (2021-11-20)
//	description: 
//		arbitration the message and then send out
//		e.g., priority= {west, east, north, south, local}
//-----------------------------------------------

`timescale 1ns / 1ps

module arbMsg(
	outR, outA, rst,
	localInR, localInA, i_localMsg_51,
	westInR, westInA, i_westMsg_51,
	eastInR, eastInA, i_eastMsg_51,
	northInR, northInA, i_southMsg_51,
	southInR, southInA, i_northMsg_51,
	o_msg_51);

input  outA, rst;
output outR;
output[50:0] o_msg_51;

input localInR;
output localInA;
input [50:0] i_localMsg_51;

input westInR;
output westInA;
input [50:0] i_westMsg_51;

input eastInR;
output eastInA;
input [50:0] i_eastMsg_51;

input northInR;
output northInA;
input [50:0] i_northMsg_51;

input southInR;
output southInA;
input [50:0] i_southMsg_51;

//---------------------------------------------------------
//inner regs and wires
 wire  w_localFifoFire_2;
 wire  w_westFifoFire_2;
 wire  w_eastFifoFire_2;
 wire  w_northFifoFire_2;
 wire  w_southFifoFire_2;

 wire decisionTap;
 wire decisionInANon;
 wire w_decisionDelayR;
 wire w_decisionDelayA;
 wire w_decisionFire;

 wire releaseTap;
 wire releaseInANon;
 wire releaseoutRNon;
 wire releaseoutANon;
 wire prerelease;
 wire [1:0]w_releaseDelayR_2;
 wire [1:0]w_releaseDelayA_2;
 wire [1:0]w_delayFire_2;

 reg [4:0] r_priority_5;
 wire[4:0] w_priority_5;

 wire localArbTrig;
 wire westArbTrig;
 wire eastArbTrig;
 wire northArbTrig;
 wire southArbTrig;
 wire trig;
 wire  delay_trig;
 wire delayTrig;

 wire localPmt;
 wire westPmt;
 wire eastPmt;
 wire northPmt;
 wire southPmt;

 wire w_choseDir;


 reg[50:0] r_localMsg_51;
 reg[50:0] r_westMsg_51;
 reg[50:0] r_eastMsg_51;
 reg[50:0] r_northMsg_51;
 reg[50:0] r_southMsg_51;

 wire[50:0] w_outMsg_51;

 wire busy;
 wire roundAgain;
 wire decisionTrig;
 wire releaseTrig;

 wire delayBusy;
 wire idle;
 wire delay_idle;
 wire arbFinish;
 wire localIdle;
 wire westIdle;
 wire eastIdle;
 wire northIdle;
 wire southIdle;

 wire delay_westPmt;
 wire delay_eastPmt;
 wire delay_northPmt;
 wire delay_southPmt;
 wire delay_localPmt;

 wire localTap;
 wire westTap;
 wire eastTap;
 wire northTap;
 wire southTap;

 wire localSetReq;
 wire westSetReq;
 wire eastSetReq;
 wire northSetReq;
 wire southSetReq;

 wire localResetReq;
 wire westResetReq;
 wire eastResetReq;
 wire northResetReq;
 wire southResetReq;

 wire localReqTrig;
 wire westReqTrig;
 wire eastReqTrig;
 wire northReqTrig;
 wire southReqTrig;

 wire[4:0] validation_5;
 wire w_isValid;
 wire isvalid;
 reg[50:0] r_outMsg_51;

 wire decideoutR;
 wire decideoutA;
wire release1,release0,relrelease,delay_relrelease;
wire w_preoutFire;
wire w_outFire;

//---------------------------------------------------------
//request fifo
//localst
reqFifo localFifo(
	.inR(localInR),
	.pmt(localPmt),
	.fire_2(w_localFifoFire_2),
	.inA(localInA),
	.idle(localIdle),
	.rst(rst) );

//west
reqFifo westFifo(
	.inR(westInR),
	.pmt(westPmt),
	.fire_2(w_westFifoFire_2),
	.inA(westInA),
    .idle(westIdle),
	.rst(rst) );

//east
reqFifo eastFifo(
	.inR(eastInR),
	.pmt(eastPmt),
	.fire_2(w_eastFifoFire_2),
	.inA(eastInA),
	.idle(eastIdle),
	.rst(rst) );

//north
reqFifo northFifo(
	.inR(northInR),
	.pmt(northPmt),
	.fire_2(w_northFifoFire_2),
	.inA(northInA),
	.idle(northIdle),
	.rst(rst) );

//south
reqFifo southFifo(
	.inR(southInR),
	.pmt(southPmt),
	.fire_2(w_southFifoFire_2),
	.inA(southInA),
	.idle(southIdle),
	.rst(rst) );

assign delayBusy = ~busy;
//assign isvalid=delayBusy|w_isValid;
//delay1U delay3(.inR(delayBusy),.outR(delayIdle));
//LUT1 #(.INIT(2'b10)) inRDelay 
//( 
//   .O(delayIdle),   
//   .I0(delayBusy)  	
//);

pmtFifo pm(.inR(arbFinish),.pmt(release1),.rst(rst));
assign relrelease=release0|release1;
delay2U delay6(.inR(relrelease),.outR(delay_relrelease));
assign release0 = prerelease&arbFinish;
assign arbFinish = ~(decisionTap ^ decideoutA);
assign idle =  delayBusy;
delay8U delay5(.inR(idle),.outR(delay_idle) );

assign localIdle = delay_idle;
assign westIdle = delay_idle;
assign eastIdle = delay_idle;
assign northIdle = delay_idle;
assign southIdle = delay_idle;

//---------------------------------------------------------
//decide fifo
wire decisionTapDelay;
wire releaseTapDelay;
delay4U delaDeTap(.inR(decisionTap) , .outR(decisionTapDelay));

posClick decideFifo0(
	.inR(decisionTapDelay), 
	.inA(decisionInANon), 
	.outR(decideoutR),
	.outA(decideoutA), 
	.fire(w_decisionFire), 
	.rst(rst) );

assign outR = decideoutR;
assign decideoutA = outA;
//LUT1 #(.INIT(2'b10)) tmp 
//(
//   .O(outA),   
//   .I0(outR)  
//);


//---------------------------------------------------------
//---------------------------------------------------------
//release fifo

//---------------------------------------------------------
//delay2
delay4U delaReTap(.inR(releaseTap) , .outR(releaseTapDelay));
posClick delayClick0(
	.inR(releaseTapDelay), 
	.inA(releaseInANon), 
	.outR(w_releaseDelayR_2[0]),
	.outA(w_releaseDelayA_2[0]), 
	.fire(w_delayFire_2[0]), 
	.rst(rst) );

posClick delayClick1(
     .inR(w_releaseDelayR_2[0]), 
     .inA(w_releaseDelayA_2[0]), 
     .outR(w_releaseDelayR_2[1]),
     .outA(w_releaseDelayA_2[1]), 
     .fire(w_delayFire_2[1]), 
     .rst(rst) );

//----------------------------------------------------------

posClick releaseFifo0(
	.inR(w_releaseDelayR_2[1]), 
	.inA(w_releaseDelayA_2[1]), 
	.outR(releaseoutRNon),
	.outA(releaseoutANon), 
	.fire(prerelease), 
	.rst(rst) );

assign releaseoutANon = releaseoutRNon;
//---------------------------------------------------------
//round arbiter
assign localArbTrig = w_localFifoFire_2;
assign westArbTrig = w_westFifoFire_2;
assign eastArbTrig = w_eastFifoFire_2;
assign northArbTrig = w_northFifoFire_2;
assign southArbTrig = w_southFifoFire_2;

assign trig = localArbTrig |
	westArbTrig | eastArbTrig |
	northArbTrig | southArbTrig |
	roundAgain;

//generate local priority
//		5'b10000 -> 
//		5'b01000 ->
//		5'b00100 ->
//		5'b00010 ->
//		5'b00001 -> back(5'b10000)
always@(posedge trig or negedge rst)
begin
	if(!rst)
		r_priority_5 = 5'b00000;
	else
	    if(r_priority_5 == 5'b00000)
            r_priority_5 = 5'b10000;
        else
		if(r_priority_5 == 5'b10000)
			r_priority_5 = 5'b01000;
		else
		if(r_priority_5 == 5'b01000)
			r_priority_5 = 5'b00100;
		else
		if(r_priority_5 == 5'b00100)
			r_priority_5 = 5'b00010;
		else
		if(r_priority_5 == 5'b00010)
			r_priority_5 = 5'b00001;
		else
		if(r_priority_5 == 5'b00001)
			r_priority_5 = 5'b00000;
		else
			r_priority_5 = 5'b00000;
end 

assign w_priority_5 = r_priority_5;

//dir validation
assign validation_5[0] = w_priority_5[0]  & localTap;
assign validation_5[4] = w_priority_5[4]  & westTap;
assign validation_5[3] = w_priority_5[3]  & eastTap;
assign validation_5[2] = w_priority_5[2]  & northTap;
assign validation_5[1] = w_priority_5[1]  & southTap;

assign w_isValid = validation_5[0] | validation_5[1] | validation_5[2] | validation_5[3] | validation_5[4];
//---------------------------------------------------------
//choosing direction
assign w_choseDir = w_decisionFire;
assign w_outFire = w_decisionFire;
//delay4U delay8(.inR(w_preoutFire), .outR(w_outFire));

assign localPmt = w_priority_5[0] & w_choseDir & localTap;
assign westPmt = w_priority_5[4] & w_choseDir & westTap;
assign eastPmt = w_priority_5[3] & w_choseDir & eastTap;
assign northPmt = w_priority_5[2] & w_choseDir & northTap;
assign southPmt = w_priority_5[1] & w_choseDir & southTap;


//---------------------------------------------------------
//message transfer
//local
always@(posedge localArbTrig or negedge rst)
begin
	if(!rst)
		r_localMsg_51 = 51'b0;
	else
		r_localMsg_51 = i_localMsg_51;
end

//west
always@(posedge westArbTrig or negedge rst)
begin
	if(!rst)
		r_westMsg_51 = 51'b0;
	else
		r_westMsg_51 = i_westMsg_51;
end

//east
always@(posedge eastArbTrig or negedge rst)
begin
	if(!rst)
		r_eastMsg_51 = 51'b0;
	else
		r_eastMsg_51 = i_eastMsg_51;
end

//north
always@(posedge northArbTrig or negedge rst)
begin
	if(!rst)
		r_northMsg_51 = 51'b0;
	else
		r_northMsg_51 = i_northMsg_51;
end

//south
always@(posedge southArbTrig or negedge rst)
begin
	if(!rst)
		r_southMsg_51 = 51'b0;
	else
		r_southMsg_51 = i_southMsg_51;
end

assign w_outMsg_51 = (validation_5 == 5'b10000) ? r_westMsg_51 :
                    ((validation_5 == 5'b01000) ? r_eastMsg_51 :
                    ((validation_5 == 5'b00100) ? r_northMsg_51 :
                    ((validation_5 == 5'b00010) ? r_southMsg_51 :
                    ((validation_5 == 5'b00001) ? r_localMsg_51 : 51'b0))));

//output
always@(posedge w_outFire or negedge rst)//wbx
begin
	if(!rst)
		r_outMsg_51 = 51'b0;
	else
		r_outMsg_51 = w_outMsg_51;
end

assign o_msg_51 = r_outMsg_51;

//---------------------------------------------------------

assign busy = w_priority_5[0] | w_priority_5[1] |
	w_priority_5[2] | w_priority_5[3] |
	w_priority_5[4];

//---------------------------------
//delay1

delay2U delay1(.inR(trig), .outR(delay_trig));
//delay1U delay7(.inR(delay_trig[0]), .outR(delayTrig));
//--------------------------------------
assign decisionTrig = w_isValid & delay_trig;

assign releaseTrig = delay_trig & busy;
 
assign roundAgain = busy & delay_relrelease ;
/*
assign localSetReq = w_localFifoFire_2[1];
assign westSetReq = w_westFifoFire_2[1];
assign eastSetReq = w_eastFifoFire_2[1];
assign northSetReq = w_northFifoFire_2[1];
assign southSetReq = w_southFifoFire_2[1];
*/
assign localSetReq = w_localFifoFire_2;
assign westSetReq = w_westFifoFire_2;
assign eastSetReq = w_eastFifoFire_2;
assign northSetReq = w_northFifoFire_2;
assign southSetReq = w_southFifoFire_2;

assign localResetReq = localPmt;
assign westResetReq = westPmt;
assign eastResetReq = eastPmt;
assign northResetReq = northPmt;
assign southResetReq = southPmt;


/*delay1U delaywest(.inR(westPmt),.outR(delay_westPmt));
delay1U delayeast(.inR(eastPmt),.outR(delay_eastPmt));
delay1U delaynorth(.inR(northPmt),.outR(delay_northPmt));
delay1U delaysouth(.inR(southPmt),.outR(delay_southPmt));
delay1U delaylocal(.inR(localPmt),.outR(delay_localPmt));*/

assign localReqTrig = localSetReq | localResetReq;
assign westReqTrig = westSetReq | westResetReq;
assign eastReqTrig = eastSetReq | eastResetReq;
assign northReqTrig = northSetReq | northResetReq;
assign southReqTrig = southSetReq | southResetReq;

contTap decisionContTap(
	.trig(decisionTrig),
	.req(decisionTap),
	.rst(rst) );

contTap releaseContTap(
    .trig(releaseTrig),
    .req(releaseTap),
    .rst(rst)  );

contTap localReqContTap(
	.trig(localReqTrig),
	.req(localTap),
	.rst(rst) );

contTap westReqContTap(
	.trig(westReqTrig),
	.req(westTap),
	.rst(rst) );

contTap eastReqContTap(
	.trig(eastReqTrig),
	.req(eastTap),
	.rst(rst) );

contTap northReqContTap(
	.trig(northReqTrig),
	.req(northTap),
	.rst(rst) );

contTap southReqContTap(
	.trig(southReqTrig),
	.req(southTap),
	.rst(rst) );


//---------------------------------------------------------

endmodule
